﻿using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;

namespace PinusClientDemo.Tools
{
    public sealed class QuartzHelper
    {
        private static bool _initialized;
        private static object _lockObject;

        private static ISchedulerFactory _scheduler;
        private static IScheduler _sched;

        static QuartzHelper()
        {
            _initialized = false;
            _lockObject = new object();
        }

        private static void Initialize()
        {
            if (!_initialized)
            {
                lock (_lockObject)
                {
                    if (!_initialized)
                    {
                        _scheduler = new StdSchedulerFactory();
                        _sched = _scheduler.GetScheduler().Result;

                        _sched.Start();

                        _initialized = true;
                    }
                }
            }
        }

        private static IScheduler Sched
        {
            get
            {
                Initialize();
                return _sched;
            }
        }

        private static JobKey GetJobKey(string jobName, string groupName)
        {
            var jobKey = new JobKey($@"JobKey_{jobName}");
            if (!String.IsNullOrWhiteSpace(groupName))
                jobKey.Group = groupName;
            return jobKey;
        }

        private static TriggerKey GetTriggerKey(string triggerName, string triggerGroup)
        {
            var triggerKey = new TriggerKey($@"TriggerKey_{triggerName}");
            if (!String.IsNullOrWhiteSpace(triggerGroup))
                triggerKey.Group = triggerGroup;
            return triggerKey;
        }

        private static Tuple<JobKey, TriggerKey> GetIdentityKey(string name, string group)
            => new(GetJobKey(name, group), GetTriggerKey(name, group));

        #region AddJob

        public static void AddJob<T>(string name, string cron, string group = null) where T : IJob
        {
            AddJob<T>(name, cron, null, group);
        }

        public static void AddJob<T>(string name, string cron, string dataMapKey, object dataMapValue, string group = null) where T : IJob
        {
            var dicDataMap = new Dictionary<string, object>
            {
                { dataMapKey,dataMapValue }
            };

            AddJob<T>(name, cron, dicDataMap, group);
        }

        public static void AddJob<T>(string name, string cron, Dictionary<string, object> dataMap, string group) where T : IJob
        {
            var identityKey = GetIdentityKey(name, group);

            var job = JobBuilder.Create<T>()
                .WithIdentity(identityKey.Item1)
                .Build();
            if (dataMap is { Count: > 0 })
                job.JobDataMap.PutAll(dataMap);

            var trigger = TriggerBuilder.Create()
                .WithCronSchedule(cron)
                .WithIdentity(identityKey.Item2)
                .Build();

            Sched.ScheduleJob(job, trigger);
        }

        private static void AddJob(IJobDetail job, ITrigger trigger)
        {
            Sched.ScheduleJob(job, trigger);
        }
        #endregion

        #region DelJob

        public static void DelJob(string name, string group = null)
        {
            var identityKey = GetIdentityKey(name, group);
            DelJob(identityKey.Item1, identityKey.Item2);
        }

        private static void DelJob(JobKey jobKey, TriggerKey triggerKey)
        {
            Sched.PauseTrigger(triggerKey);
            Sched.UnscheduleJob(triggerKey);
            Sched.DeleteJob(jobKey);
        }
        #endregion
    }
}